﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FGK
{
    class Wektor
    {
        #region Konstruktor

        public Wektor() { }

        public Wektor(float x, float y, float z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public Wektor(Wektor w1, Wektor w2)
        {
            this.x = w2.X - w1.X;
            this.y = w2.Y - w1.Y;
            this.z = w2.Z - w1.Z;
        }

        public Wektor(Wektor w)
        {
            this.x = w.X;
            this.y = w.Y;
            this.z = w.Z;
        }

        #endregion Konstruktor

        #region Składowe
        private float x;
        public float X
        {
            get { return x; }
            set { x = value; }
        }

        private float y;
        public float Y
        {
            get { return y; }
            set { y = value; }
        }

        private float z;
        public float Z
        {
            get { return z; }
            set { z = value; }
        }

        #endregion Składowe

        #region Metody

        public float length()
        {
            return (float)Math.Sqrt(Math.Pow(this.x, 2) + Math.Pow(this.y, 2) + Math.Pow(this.z, 2));
        }

        public float lengthSquared()
        {
            return (float)(Math.Pow(this.x, 2) + Math.Pow(this.y, 2) + Math.Pow(this.z, 2));
        }

        public float dot(Wektor v)
        {
            return (this.x * v.x + this.y * v.y + this.z * v.z);
        }

        public Wektor cross(Wektor v)
        {
            return new Wektor(
                              this.y * v.z - this.z * v.y,
                              this.z * v.x - this.x * v.z,
                              this.x * v.y - this.y * v.x
                              );
        }

        public void negate()
        {
            this.x = -this.x;
            this.y = -this.y;
            this.z = -this.z;
        }

        public void add(Wektor v)
        {
            this.x += v.X;
            this.y += v.Y;
            this.z += v.Z; 
        }

        public void sub(Wektor v)
        {
            this.x -= v.X;
            this.y -= v.Y;
            this.z -= v.Z;
        }

        public void div(float f)
        {
            if (f != 0)
            {
                this.x /= f;
                this.y /= f;
                this.z /= f;
            }
            else
            {
                throw new Exception("Błąd dzielenia przez 0");
            }
        }

        public void normalize()
        {
            float n = this.length();
            if (n != 0)
            {
                this.div(n);
            }
            else
            {
                throw new Exception("Długość wektora wynosi 0");
            }
        }

        public Wektor normalizeProduct()
        {
            Wektor newV = new Wektor(this.x, this.y, this.z);
            float n = this.length();
            if (n != 0)
            {
                newV.div(n);
                return newV;
            }
            else
            {
                throw new Exception("Nie można normalizować");
            }
        }

        public void mag(float f)
        {
            this.x *= f;
            this.y *= f;
            this.z *= f;
        }

        public Wektor mul(float f)
        {
            this.x *= f;
            this.y *= f;
            this.z *= f;
            return new Wektor(this.x, this.y, this.z);
        }

        public Wektor reflect(Wektor normal)
        {
            return this - (2 * this.dot(normal) * normal);
        }

        public static Wektor magProduct(Wektor v, float f)
        {
            return new Wektor(v.X * f, v.Y * f, v.Z * f);
        }

        public Wektor toPoint()
        {
            Wektor p = new Wektor(this.X, this.Y, this.Z);
            return p;
        }

        public Wektor lerp(Wektor v, float t)
        {
            Wektor vector = new Wektor();
            vector.x = this.x + t * (v.x - this.x);
            vector.y = this.y + t * (v.y - this.y);
            vector.z = this.z + t * (v.z - this.z);
            return vector;
        }

        public override string ToString()
        {
            return "Wektor(" + x.ToString() + "," + y.ToString() + "," + z.ToString() + ")";
        }

        #endregion Metody

        #region Operatory

        public static Wektor operator *(float scalar, Wektor right)
        {
            return new Wektor(right.x * scalar, right.y * scalar, right.z * scalar);
        }

        public static Wektor operator *(Wektor left, float scalar)
        {
            return new Wektor(left.x * scalar, left.y * scalar, left.z * scalar);
        }

        public static Wektor operator *(Wektor left, Wektor right)
        {
            return new Wektor(left.x * right.x, left.y * right.y, left.z * right.z);
        }

        public static Wektor operator +(Wektor left, Wektor right)
        {
            return new Wektor(left.x + right.x, left.y + right.y, left.z + right.z);
        }

        public static Wektor operator +(float left, Wektor right)
        {
            return new Wektor(left + right.x, left + right.y, left + right.z);
        }

        public static Wektor operator -(Wektor left, Wektor right)
        {
            return new Wektor(left.x - right.x, left.y - right.y, left.z - right.z);
        }

        public static Wektor operator -(Wektor left)
        {
            return new Wektor(-left.x, -left.y, -left.z);
        }

        public static bool operator ==(Wektor left, Wektor right)
        {
            return (left.x == right.x && left.y == right.y && left.z == right.z);
        }

        public static bool operator !=(Wektor left, Wektor right)
        {
            return (left.x != right.x || left.y != right.y || left.z != right.z);
        }

        public static Wektor operator /(Wektor left, float scalar)
        {
            Wektor wektor = new Wektor();
            float inverse = 1.0f / scalar;

            wektor.x = left.x * inverse;
            wektor.y = left.y * inverse;
            wektor.z = left.z * inverse;

            return wektor;
        }

        #endregion Operatory

    }
}
